package ru.stork.vasilisa.model

import ru.stork.vasilisa.exceptions.VasilisaModelException
import ru.stork.vasilisa._
import com.yelbota.util.$lazy

object VasilisaType {

  private def _fromNode(foreingNs: Namespace, n: lang.Node): VasilisaType = n match {

    case lang.Package(localns, imports, t) => {
      // configure namespace for this trait
      val ns = foreingNs.configure(
        imports map (ImportDef.fromNode),
        localns
      )
      // call again
      fromNode(ns, t)
    }
    case t: lang.Model => Model.fromNode(foreingNs, t)
    case t: lang.Variant => Variant.fromNode(foreingNs, t)
    case _ => throw new VasilisaModelException(
      n, VasilisaModelException.ERR_INVALID_TOPLEVEL_DECLARATION)
  }

  import com.wordpress.michid.Memoize._

  val fromNode = memoize(_fromNode _)

    // Reconfigure ns with private declaraions
  def nsReconfigureWithPrivates(ns: Namespace, t:lang.TypeNode) = ns.addPrivateDeclarations(
    t.declarations
      .collect { case x: lang.TypeNode => x }
      .map ( x => (x.name, $lazy { VasilisaType.fromNode(ns, x) } ) ) toMap
  )
}

abstract class VasilisaType(val ns: Namespace,
                            val name: String,
                            val node: lang.Node,
                            val typeParameters: Set[String]) extends NotNull with Immutable